#include <iostream>
#include "GameEngine.h"

namespace sg
{
    GameEngine::GameEngine()
    {
        init();
        std::cout << "SnakeGame SnakeGame()" << std::endl;
    }
    GameEngine::~GameEngine()
    {
        clean();
        std::cout << "SnakeGame ~SnakeGame()" << std::endl;
    }
    void GameEngine::init()
    {
        this->fps = 60;
        this->isRunning = false;
        this->scene = nullptr;
        if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
        {
            std::cerr << "SDL_Init Error: " << SDL_GetError() << std::endl;
        }
        std::cout << "SDL Initialized" << std::endl;
        this->window = SDL_CreateWindow("Snake Game",
                                        SDL_WINDOWPOS_CENTERED,
                                        SDL_WINDOWPOS_CENTERED,
                                        500, 500,
                                        SDL_WINDOW_SHOWN);
        if (this->window == NULL)
        {
            std::cerr << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
        }

        std::cout << "Window Created" << std::endl;
        this->renderer = SDL_CreateRenderer(this->window, -1, SDL_RENDERER_SOFTWARE);
        if (this->renderer == NULL)
        {
            std::cerr << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
        }

        std::cout << "Renderer Created" << std::endl;
    }
    void GameEngine::setScene(Scene *scene)
    {
        if (this->scene != nullptr)
        {
            delete this->scene;
        }
        this->scene = scene;
    }
    void GameEngine::run()
    {
        std::cout << "GameEngine::run()" << std::endl;
        if (this->isRunning)
        {
            throw std::runtime_error("Game is already running");
        }
        if (scene == nullptr)
        {
            throw std::runtime_error("Scene is not set");
        }
        this->isRunning = true;
        std::cout << "Game Running" << std::endl;

        // 游戏循环开始的时间
        unsigned int lastTime = SDL_GetTicks();

        while (this->isRunning)
        {
            // 清屏
            SDL_SetRenderDrawColor(this->renderer, 255, 255, 255, 255);
            SDL_RenderClear(this->renderer);

            // 事件处理
            SDL_Event event;
            if (SDL_PollEvent(&event))
            {
                switch (event.type)
                {
                case SDL_QUIT:
                    this->isRunning = false;
                    break;
                default:
                    break;
                }
                // 事件处理
                scene->handleEvent(event);
            }
            // 更新
            scene->update();
            // 渲染
            scene->render();

            // 更新屏幕
            SDL_RenderPresent(this->renderer);

            // 控制帧率为60
            int frameDelay = 1000 / this->fps;
            // 当前时间与上次时间差
            unsigned int frameTime = SDL_GetTicks() - lastTime;
            if (frameTime < frameDelay)
            {
                // std::cout << "Frame Delay: " << frameDelay << "ms" << std::endl;
                SDL_Delay(frameDelay - frameTime);
            }
            lastTime = SDL_GetTicks();
        }
    }
    void GameEngine::clean()
    {
        SDL_DestroyWindow(this->window);
        SDL_DestroyRenderer(this->renderer);
        SDL_Quit();
        delete this->scene;
    }

    bool GameEngine::getIsRunning()
    {
        return this->isRunning;
    }
    SDL_Renderer *GameEngine::getRenderer()
    {
        return this->renderer;
    }
    void GameEngine::setIsRunning(bool isRunning)
    {
        this->isRunning = isRunning;
    }

    void GameEngine::setFPS(int fps)
    {
        this->fps = fps;
    }

    float GameEngine::getCurrentFPS()
    {
        // SDL 获取当前帧率
        static Uint64 lastTime = SDL_GetPerformanceCounter();
        Uint64 currentTime = SDL_GetPerformanceCounter();
        Uint64 elapsedTime = currentTime - lastTime;
        lastTime = currentTime;
        float fps = 1000.0 / (elapsedTime / (double)SDL_GetPerformanceFrequency()) / 1000;
        return fps;
    }
}